/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package simple;

import algorithm.AlgorithmErrorException;
import algorithm.PopulationBreeder;
import algorithm.*;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Pierre
 */
public class SimpleGeneticAlgorithm implements Algorithm {
    private Population currentPopulation;
    private PopulationInitializer initializer;
    private StopCriterion stopCriterion;
    private PopulationBreeder crossOverBreeder;
    private PopulationBreeder mutationBreeder;
    private AlgorithmState state;
    private Environment environment;
    private List<GenerationReport> generationReports = new ArrayList<GenerationReport>();
    private List<EndReport> endReports = new ArrayList<EndReport>();

    public SimpleGeneticAlgorithm(
            PopulationInitializer initializer, 
            StopCriterion stopCriterion, 
            PopulationBreeder crossOverBreeder, 
            PopulationBreeder mutationBreeder,
            Environment environment) {
        this.initializer = initializer;
        this.stopCriterion = stopCriterion;
        this.crossOverBreeder = crossOverBreeder;
        this.mutationBreeder = mutationBreeder;
        this.state = new AlgorithmState();
        this.environment = environment;
    }

    
    public void run() throws AlgorithmErrorException {
        initialize();
        while (!isDone()) {
            produceNextGeneration();
        }
        for (EndReport endReport : endReports) {
            endReport.write(currentPopulation,environment);
        }
    }

    public void initialize() throws AlgorithmErrorException {
        currentPopulation = initializer.createInitialPopulation();
    }

    public void produceNextGeneration() throws AlgorithmErrorException {
        // create a new population by crossover
        Population crossedPopulation = crossOverBreeder.createNewPopulation(currentPopulation,currentPopulation,environment, initializer.getSize());
        Population mutatedPopulation = mutationBreeder.createNewPopulation(crossedPopulation, null,environment, initializer.getSize());
        currentPopulation = mutatedPopulation;
        for (GenerationReport report : generationReports) {
            report.write(currentPopulation, environment);
        }
        state.addGeneration();
    }

    public boolean isDone() {
        return stopCriterion.isDone(state);
    }

    public void addEndReport(EndReport report) {
        endReports.add(report);
    }

    public void addGenerationReport(GenerationReport report) {
        generationReports.add(report);
    }

    public Population getPopulation() {
        return currentPopulation;
    }
    
    public Environment getEnvironment() {
        return environment;
    }
    
}
